package com.springcloud.test;

import com.springcloud.anno.DuplicateSubmit;
import com.springcloud.test.model.Stu;
import com.springcloud.util.RedisEntry;
import com.springcloud.util.RedisExpire;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Aspect
public class PreDubplicateAspect {

    // 模拟 redis的 操作
    private static final Map<RedisEntry, RedisExpire> preMap = new ConcurrentHashMap<RedisEntry, RedisExpire>();


    @Pointcut("@annotation(com.springcloud.anno.DuplicateSubmit)")
    public void preventDuplication(){}


    @Around("preventDuplication()")
    public Object  prevent(ProceedingJoinPoint point) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Assert.notNull(request, "request cannot be null.");

        Object[] args = point.getArgs();
        //类名
        String params = null;
        for (Object arg : args) {
            //方法入参是否包含Map
            if (arg != null && arg instanceof HashMap) {
                params = arg.toString();
            }
        }
        String url = request.getRequestURI();
        Map<String, String> map = new HashMap<>();
        map.put(url, params);
        //获取执行方法
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        String token = "USER-TOKEN";
        String ip = getIpAddr(request);
        String redisKey = "PREFIX"
                .concat(ip)
                .concat(map.toString()).concat(token);
        DuplicateSubmit duplicateSubmitAnno = method.getAnnotation(DuplicateSubmit.class);
        String redisValue = "prevent duplication submit".concat(duplicateSubmitAnno.value());
        RedisEntry redisEntry = new RedisEntry(redisKey,redisValue);
        if(!preMap.containsKey(redisEntry)){
            System.out.println("这个方法可以正常访问2");
            preMap.put(redisEntry,new RedisExpire(duplicateSubmitAnno.expireSeconds()));
            return point.proceed(point.getArgs());
        }else{
            RedisExpire redisExpire = preMap.get(redisEntry);
            if(redisExpire.isExpire()){
                preMap.put(redisEntry,new RedisExpire(duplicateSubmitAnno.expireSeconds()));
                System.out.println("这个方法可以正常访问1");
                return point.proceed(point.getArgs());
            }else{
                System.out.println("这个方法被频繁访问,请稍后重试:"+method.getName()+",url:"+request.getRequestURI());
                Stu stu  = new Stu();
                stu.setStuName("{'code':-1,'msg':'error:重复提交:"+method.getName()+"'}");
                return stu;
            }
        }
    }

    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0
                || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0
                || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0
                || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1")
                    || ipAddress.equals("0:0:0:0:0:0:0:1")) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = inet.getHostAddress();
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
            // = 15
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }


}
